/************************************************************************
 * voipd by Markus Weissbacher weissbacher at gmail dot com		*
 * 									*
 * This program is Free Software, released under the GNU General	*
 * Public License v2.0 http://www.gnu.org/licenses/gpl 			*
 *									*
 * This program is an voip (sip) client to be an example of how		*
 * a sip client can work. It also aims for being a minimal voip		*
 * client allowing a easy portation and adaption to anybody's		*
 * needs, with the least possible overhead.				*
 *									*
 * This program requires:						*
 * libosip								*
 * libeXosip								*
 * libortp								*
 * and maybe speex in the future as it is an awesome codec		*
 *									*
 ************************************************************************/

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <modbus/modbus.h>

/*socket definitions*/
#define		SOCKET_ERROR        -1
#define		BUFFER_SIZE         100
#define		HOST_NAME_SIZE      255

/*modbus mapping*/
#define		MODBUS_ADDR	"10.20.255.132"
#define 	HHIGH		8
#define 	HLOW		4
#define		VLEFT		1
#define		VRIGHT		2
#define		FINGER_OPEN	256
#define		FINGER_CLOSE	512

/*global variables*/
int	hSocket;                 /* handle to socket */

void modbus_call(int number);
void sighandler();

int  main(int argc, char* argv[])
{
	char* 	stringreturn;
	struct 	hostent* pHostInfo;   /* holds info about a machine */
	struct 	sockaddr_in Address;  /* Internet socket address stuct */
	long 	nHostAddress;
	char 	pBuffer[BUFFER_SIZE];
	unsigned nReadAmount;
	char 	strHostName[HOST_NAME_SIZE];
	int 	nHostPort;
	int 	number;

	strcpy(strHostName, "localhost");	/*connect to localhost*/
	nHostPort=20000;			/*at port 20000 (voipd default port)*/

	/* make a socket */
	hSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

	if(hSocket == SOCKET_ERROR)
	{
		printf("Could not make a socket\n");
		return 0;
	}
	/* get IP address from name */
	pHostInfo=gethostbyname(strHostName);
	/* copy address into long */
	memcpy(&nHostAddress,pHostInfo->h_addr,pHostInfo->h_length);

	/* fill address struct */
	Address.sin_addr.s_addr=nHostAddress;
	Address.sin_port=htons(nHostPort);
	Address.sin_family=AF_INET;

	/* connect to host */
	if(connect(hSocket,(struct sockaddr*)&Address,sizeof(Address)) == SOCKET_ERROR)
	{
		printf("\nCould not connect to host\n");
		return 0;
	}

	/*redirect all incoming signals to sighandler to prevent a crash*/
	signal(SIGPIPE, sighandler);
	signal(SIGTERM, sighandler);
	signal(SIGINT, sighandler);

	/*demonize*/
	int cpid = fork ();
	if (cpid)
	_exit(0);
	close(0);
	close(1);
	close(2); 
 
	while(SOCKET_ERROR!=(nReadAmount=read(hSocket,pBuffer,BUFFER_SIZE)))
	{
		/*parse sent information to a number and call modbus_call to react appropriately*/
		stringreturn=(char*)(strstr(pBuffer, "\"")+1);
		stringreturn[2]='\0';
		printf("number \"%d\"\n", (number=atoi(stringreturn)));
		modbus_call(number);
	} 
	printf("\nClosing socket\n");
	/* close socket */                       
	if(close(hSocket) == SOCKET_ERROR)
	{
		printf("\nCould not close socket\n");
	}
	return 0;
}

/*send input to the modbus client*/
int modbus_set(uint16_t input)
{
        int ret;
        int nb_fail;
        int addr;
        int nb=1;
        uint16_t tab_rq_registers;
        uint16_t tab_rp_registers;
        modbus_param_t mb_param;

        /* TCP */
        modbus_init_tcp(&mb_param, MODBUS_ADDR, 502);
        if (modbus_connect(&mb_param) == -1) 
	{
		/*connection failed*/
                return -1;
        }
        nb_fail=0;
	addr=256;

	tab_rq_registers = (uint16_t) input%65536;	/*delete all bits above 16bits because everything else could produce weird failures*/
	
	nb=0;
	ret = preset_single_register(&mb_param, 0x11, addr, tab_rq_registers);
	if (ret != 1) 
	{
		nb_fail++;
	}
	else
	{
		ret = read_holding_registers(&mb_param, 0x11, addr, 1, &tab_rp_registers);
		if (ret != 1) 
		{
			nb_fail++;
		}
		else
		{
			if (tab_rq_registers != tab_rp_registers) 
			{
				nb_fail++;
			}
		}
	}
        /* Close the connection */
        modbus_close(&mb_param);
	return nb_fail;
}

/*associate dtmf numbers with modbus bits*/
void modbus_call(int number)
{
	switch (number)
	{
		/*make the cylinder go up*/
		case 2:
			modbus_set(HHIGH);/*8*/
		break;
		/*make the cylinder go left*/
		case 4:
			modbus_set(VLEFT);/*1*/
		break;
		/*make the cylinder go right*/
		case 6:
			modbus_set(VRIGHT);/*4*/
		break;
		/*make the cylinder go down*/
		case 8:
			modbus_set(HLOW);/*2*/
		break;
		default:
			printf("unhandled case %d\n", number);
	}
}

/*kill the process if something got wrong*/
void sighandler()
{
	printf("killed by handler\n");
	if(close(hSocket) == SOCKET_ERROR)
	{
		printf("\nCould not close socket\n");
	}
	_exit(0);
}
